import io
from datetime import datetime

import pandas as pd
from fastapi import UploadFile
from sqlalchemy.ext.asyncio import AsyncSession

from exceptions.exception import ServiceException
from module_admin.entity.vo.common_vo import CrudResponseModel
from module_stock.dao.account_dao import AccountDao
from module_stock.dao.settlement_dao import SettlementDao
from module_stock.dao.stat_position_dao import StatPositionDao
from module_stock.dao.stat_stock_dao import StatStockDao
from module_stock.entity.vo.account_vo import AccountPageQueryModel
from module_stock.entity.vo.settlement_vo import DeleteSettlementModel, SettlementModel, SettlementPageQueryModel
from module_stock.entity.vo.stat_position_vo import StatPositionModel
from module_stock.entity.vo.stat_stock_vo import StatStockModel


class SettlementService:
    """
    交易交割记录模块服务层
    """

    @classmethod
    async def get_settlement_list_services(
            cls, query_db: AsyncSession, query_object: SettlementPageQueryModel, is_page: bool = False
    ):
        """
        获取交易交割记录列表信息service

        :param query_db: orm对象
        :param query_object: 查询参数对象
        :param is_page: 是否开启分页
        :return: 交易交割记录列表信息对象
        """
        settlement_list_result = await SettlementDao.get_settlement_list(query_db, query_object, is_page)

        return settlement_list_result

    @classmethod
    async def add_settlement_services(cls, query_db: AsyncSession, page_object: SettlementModel):
        """
        新增交易交割记录信息service

        :param query_db: orm对象
        :param page_object: 新增交易交割记录对象
        :return: 新增交易交割记录校验结果
        """
        try:
            await SettlementDao.add_settlement_dao(query_db, page_object)
            await query_db.commit()
            return CrudResponseModel(is_success=True, message='新增成功')
        except Exception as e:
            await query_db.rollback()
            raise e

    @classmethod
    async def delete_settlement_services(cls, query_db: AsyncSession, page_object: DeleteSettlementModel):
        """
        删除交易交割记录信息service

        :param query_db: orm对象
        :param page_object: 删除交易交割记录对象
        :return: 删除交易交割记录校验结果
        """
        if page_object.ids:
            id_list = page_object.ids.split(',')
            try:
                for id in id_list:
                    await SettlementDao.delete_settlement_dao(query_db, SettlementModel(id=id))
                await query_db.commit()
                return CrudResponseModel(is_success=True, message='删除成功')
            except Exception as e:
                await query_db.rollback()
                raise e
        else:
            raise ServiceException(message='传入主键ID为空')

    @classmethod
    async def get_stock_settlement_list(cls, query_db: AsyncSession, stock_code: str, account_tag: str):
        """
        根据证券代码和账户标签获取交易明细

        :param query_db: orm对象
        :param stock_code: 证券代码
        :param account_tag: 账户标签
        :return: 交易明细列表
        """
        # 根据account_tag获取对应的account_nos
        account_list = await AccountDao.get_account_list(query_db, AccountPageQueryModel(), is_page=False)
        account_nos = [account['accountNo'] for account in account_list if account.get('accountTag') == account_tag]
        if not account_nos:
            return []

        # 获取买入和卖出记录
        buy_records, sell_records = await SettlementDao.get_buy_and_sell_settlement_list_dao(query_db, stock_code,
                                                                                             account_nos)
        # 合并记录
        all_records = list(buy_records) + list(sell_records)
        # 按照交易日期排序
        all_records.sort(key=lambda x: x.get('tradeDate'))

        return all_records

    @classmethod
    async def generate_stat_stock_services(cls, query_db: AsyncSession, stat_date: str):
        """
        根据从指定日期开始的结算数据生成股票统计数据

        :param query_db: orm对象
        :param stat_date: 开始日期，格式为 'YYYY-MM-DD'
        :return: 生成结果
        """
        await StatStockDao.clear_stat_stock_dao(query_db)
        await query_db.commit()

        await StatPositionDao.clear_stat_position_dao(query_db, stat_date)
        await query_db.commit()

        account_list = await AccountDao.get_account_list(query_db, AccountPageQueryModel(), is_page=False)
        account_tags = list(set(account['accountTag'] for account in account_list if account.get('accountTag')))
        generated_count = 0
        for account_tag in account_tags:
            # 获取该标签下的所有账号
            accounts_with_tag = [account for account in account_list if account.get('accountTag') == account_tag]
            account_nos = [account['accountNo'] for account in accounts_with_tag]
            if not account_nos:
                continue

            # 获取从指定日期开始交易的唯一证券代码列表
            stock_info_list = await SettlementDao.get_unique_stock(query_db, account_nos, stat_date)
            for stock_info in stock_info_list:
                stock_code = stock_info['stock_code']
                stock_name = stock_info['stock_name']
                # 初始化统计数据
                total_buy_amount = 0
                total_buy_quantity = 0
                total_sell_amount = 0
                total_sell_quantity = 0

                # 查询这些账号下该证券的交易记录
                # 计算买入总额、买入总量
                buy_records, sell_records = await SettlementDao.get_buy_and_sell_settlement_list_dao(query_db,
                                                                                                     stock_code,
                                                                                                     account_nos,
                                                                                                     stat_date)

                for record in buy_records:
                    if record.get('operation') == '新股入账':
                        # 新股入账，Excel报表中没有入账金额需手动计算，并且计算出来为正数，需改为负数
                        total_buy_amount += -float(record.get('tradeQuantity') * record.get('averagePrice'))
                    if record.get('tradeAmount'):
                        total_buy_amount += float(record.get('occurredAmount'))
                    if record.get('tradeQuantity'):
                        total_buy_quantity += float(record.get('tradeQuantity'))

                for record in sell_records:
                    if record.get('tradeAmount'):
                        total_sell_amount += float(record.get('occurredAmount'))
                    if record.get('tradeQuantity'):
                        total_sell_quantity += float(record.get('tradeQuantity'))

                if total_buy_quantity + total_sell_quantity != 0:
                    stat_position_model = StatPositionModel(
                        tradeDate=stat_date,
                        stockCode=stock_code,
                        stockName=stock_name,
                        accountTag=account_tag,
                        amount=round(total_buy_amount + total_sell_amount, 2),
                        quantity=total_buy_quantity + total_sell_quantity,
                        createTime=datetime.now(),
                    )
                    await StatPositionDao.add_stat_position_dao(query_db, stat_position_model)

                # 只生成今天的清仓数据（避免跟着历史持仓统计不断生成历史数据并清空）
                if stat_date != datetime.today().strftime('%Y-%m-%d'):
                    continue

                profit = total_sell_amount + total_buy_amount

                # 创建或更新股票统计记录
                stat_stock_model = StatStockModel(
                    stockCode=stock_code,
                    stockName=stock_name,
                    accountTag=account_tag,
                    totalBuyAmount=round(total_buy_amount, 2),
                    totalBuyQuantity=total_buy_quantity,
                    totalSellAmount=round(total_sell_amount, 2),
                    totalSellQuantity=total_sell_quantity,
                    profit=round(profit, 2),
                    createTime=datetime.now(),
                )
                await StatStockDao.add_stat_stock_dao(query_db, stat_stock_model)
                generated_count += 1
            await query_db.commit()
        return CrudResponseModel(is_success=True, message=f'成功生成{generated_count}条股票统计数据')

    @classmethod
    async def batch_import_settlement_services(
            cls,
            query_db: AsyncSession,
            file: UploadFile,
    ):
        """
        批量导入交易交割记录service

        :param query_db: orm对象
        :param file: 交易交割记录导入文件对象
        :return: 批量导入交易交割记录结果
        """
        header_dict = {
            '账号': 'account_no',
            '成交日期': 'trade_date',
            '证券代码': 'stock_code',
            '证券名称': 'stock_name',
            '操作': 'operation',
            '成交数量': 'trade_quantity',
            '成交编号': 'trade_no',
            '成交均价': 'average_price',
            '成交金额': 'trade_amount',
            '余额': 'balance',
            '发生金额': 'occurred_amount',
            '手续费': 'commission',
            '印花税': 'stamp_duty',
            '其他杂费': 'other_fees',
            '本次金额': 'current_amount',
            '合同编号': 'contract_no',
            '证管费': 'regulatory_fee',
            '经手费': 'handling_fee',
            '其他费用': 'other_charges',
            '交易市场': 'exchange',
            '费用合计': 'total_fees',
        }
        contents = await file.read()
        df = pd.read_excel(io.BytesIO(contents), dtype=str)
        await file.close()
        df.rename(columns=header_dict, inplace=True)
        df = df.where(pd.notnull(df), None)
        success_count = 0
        try:
            for index, row in df.iterrows():
                trade_date_value = row['trade_date']
                trade_date_value = datetime.strptime(trade_date_value, '%Y%m%d')
                import_time = datetime.now()
                exchange = row.get('exchange')
                stock_code = row.get('stock_code')
                if stock_code and exchange and isinstance(exchange, str):
                    if '上海' in exchange:
                        stock_code = stock_code + ".SH"
                    elif '深圳' in exchange:
                        stock_code = stock_code + ".SZ"
                    elif 'HK' in exchange:
                        stock_code = stock_code + ".HK"

                add_settlement = SettlementModel(
                    accountNo=row.get('account_no'),
                    tradeDate=trade_date_value,
                    stockCode=stock_code,
                    stockName=row['stock_name'],
                    operation=row['operation'],
                    tradeQuantity=row['trade_quantity'],
                    tradeNo=row['trade_no'],
                    averagePrice=row['average_price'],
                    tradeAmount=row['trade_amount'],
                    balance=row['balance'],
                    occurredAmount=row['occurred_amount'],
                    commission=row['commission'],
                    stampDuty=row['stamp_duty'],
                    otherFees=row['other_fees'],
                    currentAmount=row['current_amount'],
                    contractNo=row['contract_no'],
                    regulatoryFee=row['regulatory_fee'],
                    handlingFee=row['handling_fee'],
                    otherCharges=row['other_charges'],
                    exchange=exchange,
                    totalFees=row['total_fees'],
                    createTime=import_time,
                    updateTime=import_time,
                )
                await cls.add_settlement_services(query_db, add_settlement)
                success_count += 1
            await query_db.commit()
            return CrudResponseModel(is_success=True, message=f'导入成功，共导入{success_count}条记录')
        except Exception as e:
            await query_db.rollback()
            raise e
